#include <map>
#include <list>
#include <vector>
#include <chrono>
#include <string>
#include <thread>
#include <iostream>
#include <unordered_map>
#include "CLinkedMap.hpp"
#include "CLinkedLowMap.hpp"
#include "CLinkedHashMap.hpp"

using namespace std;

class BidirectionalMap
{
public:
    void make_map(const std::string &mapPrefix, const std::string &oneKey, const std::string &oneValue, const std::string &twoKey, const std::string &twoValue)
    {
        std::string forwardKey = mapPrefix + "_" + oneKey + "2" + twoKey + "_" + oneValue;
        std::string reverseKey = mapPrefix + "_" + twoKey + "2" + oneKey + "_" + twoValue;
        forwardMap.emplace(forwardKey, twoValue);
        reverseMap.emplace(reverseKey, oneValue);
        bidirectionalMap.emplace(forwardKey, twoValue);
        bidirectionalMap.emplace(reverseKey, oneValue);
    }
    std::unordered_map<std::string, std::string> getMap()
    {
        return bidirectionalMap;
    }

    const std::string &getValue(const std::string &mapPrefix, const std::string &oneKey, const std::string &twoKey, const std::string &oneValue) const
    {
        std::string uniqueKey = mapPrefix + "_" + oneKey + "2" + twoKey + "_" + oneValue;
        return bidirectionalMap.at(uniqueKey);
    }

    bool containsValue(const std::string &mapPrefix, const std::string &oneKey, const std::string &twoKey, const std::string &oneValue) const
    {
        std::string uniqueKey = mapPrefix + "_" + oneKey + "2" + twoKey + "_" + oneValue;
        return bidirectionalMap.find(uniqueKey) != bidirectionalMap.end();
    }

private:
    std::unordered_map<std::string, std::string> forwardMap;       // For forward mapping
    std::unordered_map<std::string, std::string> reverseMap;       // For reverse mapping
    std::unordered_map<std::string, std::string> bidirectionalMap; // For bidirect mapping
};

inline bool hasBitmap(const vector<char> &vBitmap, int pos)
{
    vector<char>::size_type charPos = pos / 8;
    if (charPos >= vBitmap.size())
        return false;
    int bitPos = 7 - pos % 8;
    return vBitmap[charPos] & (1 << bitPos);
}

class Base
{
public:
    int age;
    std::string name;
};

int test01()
{
    std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
    std::map<std::string, Base> linkedHashMap;
    for (int i = 0; i < 100 * 10000; i++)
    {
        linkedHashMap["2"].age = 2;
        linkedHashMap["2"].name = "a2";
        linkedHashMap["1"].age = 1;
        linkedHashMap["1"].name = "a1";
        linkedHashMap["4"].age = 4;
        linkedHashMap["4"].name = "a4";
        linkedHashMap["5"].age = 5;
        linkedHashMap["5"].name = "a5";
        linkedHashMap["3"].age = 3;
        linkedHashMap["3"].name = "a3";
    }
    std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed = end - start;
    std::cout << "map Elapsed time: " << elapsed.count() << "s" << std::endl;
    for (auto it = linkedHashMap.begin(); it != linkedHashMap.end(); ++it)
    {
        std::cout << it->first << ":" << it->second.name << " " << it->second.age << std::endl;
    }
    return 0;
}
int test02()
{
    std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
    CLinkedMap<std::string, Base> linkedHashMap;
    for (int i = 0; i < 100 * 10000; i++)
    {
        linkedHashMap["2"].age = 2;
        linkedHashMap["2"].name = "a2";
        linkedHashMap["1"].age = 1;
        linkedHashMap["1"].name = "a1";
        linkedHashMap["4"].age = 4;
        linkedHashMap["4"].name = "a4";
        linkedHashMap["5"].age = 5;
        linkedHashMap["5"].name = "a5";
        linkedHashMap["3"].age = 3;
        linkedHashMap["3"].name = "a3";
    }
    std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed = end - start;
    std::cout << "CLinkedMap Elapsed time: " << elapsed.count() << "s" << std::endl;
    for (auto it = linkedHashMap.begin(); it != linkedHashMap.end(); ++it)
    {
        std::cout << it->first << ":" << it->second.name << " " << it->second.age << std::endl;
    }
    return 0;
}
int test03()
{
    std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
    CLinkedLowMap<std::string, Base> linkedHashMap;
    for (int i = 0; i < 100 * 10000; i++)
    {
        linkedHashMap["2"].age = 2;
        linkedHashMap["2"].name = "a2";
        linkedHashMap["1"].age = 1;
        linkedHashMap["1"].name = "a1";
        linkedHashMap["4"].age = 4;
        linkedHashMap["4"].name = "a4";
        linkedHashMap["5"].age = 5;
        linkedHashMap["5"].name = "a5";
        linkedHashMap["3"].age = 3;
        linkedHashMap["3"].name = "a3";
    }
    std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed = end - start;
    std::cout << "CLinkedLowMap Elapsed time: " << elapsed.count() << "s" << std::endl;
    for (auto it = linkedHashMap.begin(); it != linkedHashMap.end(); ++it)
    {
        std::cout << it->first << ":" << it->second.name << " " << it->second.age << std::endl;
    }
    return 0;
}

#define PRE_COMMMAP "CommMap"
int main()
{
    BidirectionalMap mmap;
    mmap.make_map(PRE_COMMMAP, "uid", "sg_ffa352", "mobile", "18800001001");
    std::unordered_map<std::string, std::string> relationshipKey = mmap.getMap();

    for (auto it = relationshipKey.begin(); it != relationshipKey.end(); ++it)
    {
        cout << "key: " << it->first << ", value: " << it->second << endl;
    }

    if (mmap.containsValue(PRE_COMMMAP, "uid", "mobile", "sg_ffa352"))
    {
        cout << "Key:" << mmap.getValue(PRE_COMMMAP, "uid", "mobile", "sg_ffa352") << endl;
    }

    map<int, int> aa;
    aa.emplace(2, 2);
    aa.emplace(1, 1);
    aa.emplace(4, 4);
    aa.emplace(5, 5);
    aa.emplace(3, 3);
    for (auto it = aa.rbegin(); it != aa.rend(); ++it)
    {
        cout << it->first << ":" << it->second << endl;
    }
    std::thread t1(test01);
    std::thread t2(test02);
    std::thread t3(test03);

    t1.join();
    t2.join();
    t3.join();
    return 0;
}
